/* eslint-disable prefer-const,no-loss-of-precision */
'use strict'

const test = require('tape')

const big = require('../proto/big')
const fbe = require('../proto/fbe')
const int64 = require('../proto/int64')
const proto = require('../proto/proto')
const prototest = require('../proto/test')
const uuid = require('../proto/uuid')

const Big = big.Big
const Int64 = int64.Int64
const UInt64 = int64.UInt64
const UUID = uuid.UUID

test('Serialization (Final): domain', function (t) {
  // Create a new account with some orders
  let account1 = new proto.Account(1, 'Test', proto.State.good, new proto.Balance('USD', 1000.0), new proto.Balance('EUR', 100.0))
  account1.orders.push(new proto.Order(1, 'EURUSD', proto.OrderSide.buy, proto.OrderType.market, 1.23456, 1000.0))
  account1.orders.push(new proto.Order(2, 'EURUSD', proto.OrderSide.sell, proto.OrderType.limit, 1.0, 100.0))
  account1.orders.push(new proto.Order(3, 'EURUSD', proto.OrderSide.buy, proto.OrderType.stop, 1.5, 10.0))

  // Serialize the account to the FBE stream
  let writer = new proto.AccountFinalModel(new fbe.WriteBuffer())
  let serialized = writer.serialize(account1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 152)

  // Deserialize the account from the FBE stream
  let account2 = new proto.Account()
  let reader = new proto.AccountFinalModel(new fbe.ReadBuffer())
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(account2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(account2.id, 1)
  t.equal(account2.name, 'Test')
  t.true(account2.state.hasFlags(proto.State.good))
  t.equal(account2.wallet.currency, 'USD')
  t.equal(account2.wallet.amount, 1000.0)
  t.notEqual(account2.asset, undefined)
  t.equal(account2.asset.currency, 'EUR')
  t.equal(account2.asset.amount, 100.0)
  t.equal(account2.orders.length, 3)
  t.equal(account2.orders[0].id, 1)
  t.equal(account2.orders[0].symbol, 'EURUSD')
  t.true(account2.orders[0].side.eq(proto.OrderSide.buy))
  t.true(account2.orders[0].type.eq(proto.OrderType.market))
  t.equal(account2.orders[0].price, 1.23456)
  t.equal(account2.orders[0].volume, 1000.0)
  t.equal(account2.orders[1].id, 2)
  t.equal(account2.orders[1].symbol, 'EURUSD')
  t.true(account2.orders[1].side.eq(proto.OrderSide.sell))
  t.true(account2.orders[1].type.eq(proto.OrderType.limit))
  t.equal(account2.orders[1].price, 1.0)
  t.equal(account2.orders[1].volume, 100.0)
  t.equal(account2.orders[2].id, 3)
  t.equal(account2.orders[2].symbol, 'EURUSD')
  t.true(account2.orders[2].side.eq(proto.OrderSide.buy))
  t.true(account2.orders[2].type.eq(proto.OrderType.stop))
  t.equal(account2.orders[2].price, 1.5)
  t.equal(account2.orders[2].volume, 10.0)
  t.end()
})

test('Serialization (Final): struct simple', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructSimple()

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructSimpleFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 110)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 304)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructSimple()
  let reader = new prototest.StructSimpleFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 110)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1, false)
  t.equal(struct2.f2, true)
  t.equal(struct2.f3, 0)
  t.equal(struct2.f4, 0xFF)
  t.equal(struct2.f5, '\0')
  t.equal(struct2.f6, '!')
  t.equal(struct2.f7, String.fromCharCode(0))
  t.equal(struct2.f8, String.fromCharCode(0x0444))
  t.equal(struct2.f9, 0)
  t.equal(struct2.f10, 127)
  t.equal(struct2.f11, 0)
  t.equal(struct2.f12, 0xFF)
  t.equal(struct2.f13, 0)
  t.equal(struct2.f14, 32767)
  t.equal(struct2.f15, 0)
  t.equal(struct2.f16, 0xFFFF)
  t.equal(struct2.f17, 0)
  t.equal(struct2.f18, 2147483647)
  t.equal(struct2.f19, 0)
  t.equal(struct2.f20, 0xFFFFFFFF)
  t.true(struct2.f21.eq(Int64.fromNumber(0)))
  t.true(struct2.f22.eq(Int64.fromNumber(9223372036854775807)))
  t.true(struct2.f23.eq(UInt64.fromNumber(0)))
  t.true(struct2.f24.eq(UInt64.fromNumber(0xFFFFFFFFFFFFFFFF)))
  t.equal(struct2.f25, 0.0)
  t.true(Math.abs(struct2.f26 - 123.456) < 0.0001)
  t.equal(struct2.f27, 0.0)
  t.true(Math.abs(struct2.f28 - -123.567e+123) < 1e+123)
  t.true(struct2.f29.eq(new Big('0')))
  t.true(struct2.f30.eq(new Big('123456.123456')))
  t.equal(struct2.f31, '')
  t.equal(struct2.f32, 'Initial string!')
  t.equal(struct2.f33.getTime(), new Date(Date.UTC(1970, 0, 1)).getTime())
  t.equal(struct2.f34.getTime(), new Date(Date.UTC(1970, 0, 1)).getTime())
  t.true(struct2.f35.getTime() > new Date(Date.UTC(2018, 1, 1)).getTime())
  t.true(struct2.f36.eq(new UUID()))
  t.false(struct2.f37.eq(new UUID()))
  t.true(struct2.f38.eq(new UUID('123e4567-e89b-12d3-a456-426655440000')))

  t.equal(struct2.f1, struct1.f1)
  t.equal(struct2.f2, struct1.f2)
  t.equal(struct2.f3, struct1.f3)
  t.equal(struct2.f4, struct1.f4)
  t.equal(struct2.f5, struct1.f5)
  t.equal(struct2.f6, struct1.f6)
  t.equal(struct2.f7, struct1.f7)
  t.equal(struct2.f8, struct1.f8)
  t.equal(struct2.f9, struct1.f9)
  t.equal(struct2.f10, struct1.f10)
  t.equal(struct2.f11, struct1.f11)
  t.equal(struct2.f12, struct1.f12)
  t.equal(struct2.f13, struct1.f13)
  t.equal(struct2.f14, struct1.f14)
  t.equal(struct2.f15, struct1.f15)
  t.equal(struct2.f16, struct1.f16)
  t.equal(struct2.f17, struct1.f17)
  t.equal(struct2.f18, struct1.f18)
  t.equal(struct2.f19, struct1.f19)
  t.equal(struct2.f20, struct1.f20)
  t.true(struct2.f21.eq(struct1.f21))
  t.true(struct2.f22.eq(struct1.f22))
  t.true(struct2.f23.eq(struct1.f23))
  t.true(struct2.f24.eq(struct1.f24))
  t.equal(struct2.f25, struct1.f25)
  t.true(Math.abs(struct2.f26 - struct1.f26) < 0.0001)
  t.equal(struct2.f27, struct1.f27)
  t.true(Math.abs(struct2.f28 - struct1.f28) < 1e+123)
  t.true(struct2.f29.eq(struct1.f29))
  t.true(struct2.f29.eq(struct1.f29))
  t.equal(struct2.f31, struct1.f31)
  t.equal(struct2.f32, struct1.f32)
  t.equal(struct2.f33.getTime(), struct1.f33.getTime())
  t.equal(struct2.f34.getTime(), struct1.f34.getTime())
  t.equal(struct2.f35.getTime(), struct1.f35.getTime())
  t.true(struct2.f36.eq(struct1.f36))
  t.true(struct2.f37.eq(struct1.f37))
  t.true(struct2.f38.eq(struct1.f38))
  t.true(struct2.f39.eq(struct1.f39))
  t.true(struct2.f40.eq(struct1.f40))
  t.end()
})

test('Serialization (Final): struct optional', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructOptional()

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructOptionalFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 111)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 478)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructOptional()
  let reader = new prototest.StructOptionalFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 111)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1, false)
  t.equal(struct2.f2, true)
  t.equal(struct2.f3, 0)
  t.equal(struct2.f4, 0xFF)
  t.equal(struct2.f5, '\0')
  t.equal(struct2.f6, '!')
  t.equal(struct2.f7, String.fromCharCode(0))
  t.equal(struct2.f8, String.fromCharCode(0x0444))
  t.equal(struct2.f9, 0)
  t.equal(struct2.f10, 127)
  t.equal(struct2.f11, 0)
  t.equal(struct2.f12, 0xFF)
  t.equal(struct2.f13, 0)
  t.equal(struct2.f14, 32767)
  t.equal(struct2.f15, 0)
  t.equal(struct2.f16, 0xFFFF)
  t.equal(struct2.f17, 0)
  t.equal(struct2.f18, 2147483647)
  t.equal(struct2.f19, 0)
  t.equal(struct2.f20, 0xFFFFFFFF)
  t.true(struct2.f21.eq(Int64.fromNumber(0)))
  t.true(struct2.f22.eq(Int64.fromNumber(9223372036854775807)))
  t.true(struct2.f23.eq(UInt64.fromNumber(0)))
  t.true(struct2.f24.eq(UInt64.fromNumber(0xFFFFFFFFFFFFFFFF)))
  t.equal(struct2.f25, 0.0)
  t.true(Math.abs(struct2.f26 - 123.456) < 0.0001)
  t.equal(struct2.f27, 0.0)
  t.true(Math.abs(struct2.f28 - -123.567e+123) < 1e+123)
  t.true(struct2.f29.eq(new Big('0')))
  t.true(struct2.f30.eq(new Big('123456.123456')))
  t.equal(struct2.f31, '')
  t.equal(struct2.f32, 'Initial string!')
  t.equal(struct2.f33.getTime(), new Date(Date.UTC(1970, 0, 1)).getTime())
  t.equal(struct2.f34.getTime(), new Date(Date.UTC(1970, 0, 1)).getTime())
  t.true(struct2.f35.getTime() > new Date(Date.UTC(2018, 1, 1)).getTime())
  t.true(struct2.f36.eq(new UUID()))
  t.false(struct2.f37.eq(new UUID()))
  t.true(struct2.f38.eq(new UUID('123e4567-e89b-12d3-a456-426655440000')))

  t.equal(struct2.f100, undefined)
  t.notEqual(struct2.f101, null)
  t.equal(struct2.f101, true)
  t.equal(struct2.f102, undefined)
  t.equal(struct2.f103, undefined)
  t.notEqual(struct2.f104, null)
  t.equal(struct2.f104, 0xFF)
  t.equal(struct2.f105, undefined)
  t.equal(struct2.f106, undefined)
  t.notEqual(struct2.f107, null)
  t.equal(struct2.f107, '!')
  t.equal(struct2.f108, undefined)
  t.equal(struct2.f109, undefined)
  t.notEqual(struct2.f110, null)
  t.equal(struct2.f110, String.fromCharCode(0x0444))
  t.equal(struct2.f111, undefined)
  t.equal(struct2.f112, undefined)
  t.notEqual(struct2.f113, null)
  t.equal(struct2.f113, 127)
  t.equal(struct2.f114, undefined)
  t.equal(struct2.f115, undefined)
  t.notEqual(struct2.f116, null)
  t.equal(struct2.f116, 0xFF)
  t.equal(struct2.f117, undefined)
  t.equal(struct2.f118, undefined)
  t.notEqual(struct2.f119, null)
  t.equal(struct2.f119, 32767)
  t.equal(struct2.f120, undefined)
  t.equal(struct2.f121, undefined)
  t.notEqual(struct2.f122, null)
  t.equal(struct2.f122, 0xFFFF)
  t.equal(struct2.f123, undefined)
  t.equal(struct2.f124, undefined)
  t.notEqual(struct2.f125, null)
  t.equal(struct2.f125, 2147483647)
  t.equal(struct2.f126, undefined)
  t.equal(struct2.f127, undefined)
  t.notEqual(struct2.f128, null)
  t.equal(struct2.f128, 0xFFFFFFFF)
  t.equal(struct2.f129, undefined)
  t.equal(struct2.f130, undefined)
  t.notEqual(struct2.f131, null)
  t.true(struct2.f131.eq(Int64.fromNumber(9223372036854775807)))
  t.equal(struct2.f132, undefined)
  t.equal(struct2.f133, undefined)
  t.notEqual(struct2.f134, null)
  t.true(struct2.f134.eq(UInt64.fromNumber(0xFFFFFFFFFFFFFFFF)))
  t.equal(struct2.f135, undefined)
  t.equal(struct2.f136, undefined)
  t.notEqual(struct2.f137, null)
  t.true(Math.abs(struct2.f137 - 123.456) < 0.0001)
  t.equal(struct2.f138, undefined)
  t.equal(struct2.f139, undefined)
  t.notEqual(struct2.f140, null)
  t.true(Math.abs(struct2.f140 - -123.567e+123) < 1e+123)
  t.equal(struct2.f141, undefined)
  t.equal(struct2.f142, undefined)
  t.notEqual(struct2.f143, null)
  t.true(struct2.f143.eq(new Big('123456.123456')))
  t.equal(struct2.f144, undefined)
  t.equal(struct2.f145, undefined)
  t.notEqual(struct2.f146, null)
  t.equal(struct2.f146, 'Initial string!')
  t.equal(struct2.f147, undefined)
  t.equal(struct2.f148, undefined)
  t.notEqual(struct2.f149, null)
  t.true(struct2.f149.getTime() > new Date(Date.UTC(2018, 1, 1)).getTime())
  t.equal(struct2.f150, undefined)
  t.equal(struct2.f151, undefined)
  t.notEqual(struct2.f152, null)
  t.true(struct2.f152.eq(new UUID('123e4567-e89b-12d3-a456-426655440000')))
  t.equal(struct2.f153, undefined)
  t.equal(struct2.f154, undefined)
  t.equal(struct2.f155, undefined)
  t.equal(struct2.f156, undefined)
  t.equal(struct2.f157, undefined)
  t.equal(struct2.f158, undefined)
  t.equal(struct2.f159, undefined)
  t.equal(struct2.f160, undefined)
  t.equal(struct2.f161, undefined)
  t.equal(struct2.f162, undefined)
  t.equal(struct2.f163, undefined)
  t.equal(struct2.f164, undefined)
  t.equal(struct2.f165, undefined)

  t.equal(struct2.f1, struct1.f1)
  t.equal(struct2.f2, struct1.f2)
  t.equal(struct2.f3, struct1.f3)
  t.equal(struct2.f4, struct1.f4)
  t.equal(struct2.f5, struct1.f5)
  t.equal(struct2.f6, struct1.f6)
  t.equal(struct2.f7, struct1.f7)
  t.equal(struct2.f8, struct1.f8)
  t.equal(struct2.f9, struct1.f9)
  t.equal(struct2.f10, struct1.f10)
  t.equal(struct2.f11, struct1.f11)
  t.equal(struct2.f12, struct1.f12)
  t.equal(struct2.f13, struct1.f13)
  t.equal(struct2.f14, struct1.f14)
  t.equal(struct2.f15, struct1.f15)
  t.equal(struct2.f16, struct1.f16)
  t.equal(struct2.f17, struct1.f17)
  t.equal(struct2.f18, struct1.f18)
  t.equal(struct2.f19, struct1.f19)
  t.equal(struct2.f20, struct1.f20)
  t.true(struct2.f21.eq(struct1.f21))
  t.true(struct2.f22.eq(struct1.f22))
  t.true(struct2.f23.eq(struct1.f23))
  t.true(struct2.f24.eq(struct1.f24))
  t.equal(struct2.f25, struct1.f25)
  t.true(Math.abs(struct2.f26 - struct1.f26) < 0.0001)
  t.equal(struct2.f27, struct1.f27)
  t.true(Math.abs(struct2.f28 - struct1.f28) < 1e+123)
  t.true(struct2.f29.eq(struct1.f29))
  t.true(struct2.f30.eq(struct1.f30))
  t.equal(struct2.f31, struct1.f31)
  t.equal(struct2.f32, struct1.f32)
  t.equal(struct2.f33.getTime(), struct1.f33.getTime())
  t.equal(struct2.f34.getTime(), struct1.f34.getTime())
  t.equal(struct2.f35.getTime(), struct1.f35.getTime())
  t.true(struct2.f36.eq(struct1.f36))
  t.true(struct2.f37.eq(struct1.f37))
  t.true(struct2.f38.eq(struct1.f38))
  t.true(struct2.f39.eq(struct1.f39))
  t.true(struct2.f40.eq(struct1.f40))

  t.equal(struct2.f100, struct1.f100)
  t.equal(struct2.f101, struct1.f101)
  t.equal(struct2.f102, struct1.f102)
  t.equal(struct2.f103, struct1.f103)
  t.equal(struct2.f104, struct1.f104)
  t.equal(struct2.f105, struct1.f105)
  t.equal(struct2.f106, struct1.f106)
  t.equal(struct2.f107, struct1.f107)
  t.equal(struct2.f108, struct1.f108)
  t.equal(struct2.f109, struct1.f109)
  t.equal(struct2.f110, struct1.f110)
  t.equal(struct2.f111, struct1.f111)
  t.equal(struct2.f112, struct1.f112)
  t.equal(struct2.f113, struct1.f113)
  t.equal(struct2.f114, struct1.f114)
  t.equal(struct2.f115, struct1.f115)
  t.equal(struct2.f116, struct1.f116)
  t.equal(struct2.f117, struct1.f117)
  t.equal(struct2.f118, struct1.f118)
  t.equal(struct2.f119, struct1.f119)
  t.equal(struct2.f120, struct1.f120)
  t.equal(struct2.f121, struct1.f121)
  t.equal(struct2.f122, struct1.f122)
  t.equal(struct2.f123, struct1.f123)
  t.equal(struct2.f124, struct1.f124)
  t.equal(struct2.f125, struct1.f125)
  t.equal(struct2.f126, struct1.f126)
  t.equal(struct2.f127, struct1.f127)
  t.equal(struct2.f128, struct1.f128)
  t.equal(struct2.f129, struct1.f129)
  t.equal(struct2.f130, struct1.f130)
  t.true(struct2.f131.eq(struct1.f131))
  t.equal(struct2.f132, struct1.f132)
  t.equal(struct2.f133, struct1.f133)
  t.true(struct2.f134.eq(struct1.f134))
  t.equal(struct2.f135, struct1.f135)
  t.equal(struct2.f136, struct1.f136)
  t.true(Math.abs(struct2.f137 - struct1.f137) < 0.0001)
  t.equal(struct2.f138, struct1.f138)
  t.equal(struct2.f139, struct1.f139)
  t.true(Math.abs(struct2.f140 - struct1.f140) < 1e+123)
  t.equal(struct2.f141, struct1.f141)
  t.equal(struct2.f142, struct1.f142)
  t.true(struct2.f143.eq(struct1.f143))
  t.equal(struct2.f144, struct1.f144)
  t.equal(struct2.f145, struct1.f145)
  t.equal(struct2.f146, struct1.f146)
  t.equal(struct2.f147, struct1.f147)
  t.equal(struct2.f148, struct1.f148)
  t.equal(struct2.f149.getTime(), struct1.f149.getTime())
  t.equal(struct2.f150, struct1.f150)
  t.equal(struct2.f151, struct1.f151)
  t.true(struct2.f152.eq(struct1.f152))
  t.equal(struct2.f153, struct1.f153)
  t.equal(struct2.f154, struct1.f154)
  t.equal(struct2.f155, struct1.f155)
  t.equal(struct2.f156, struct1.f156)
  t.equal(struct2.f157, struct1.f157)
  t.end()
})

test('Serialization (Final): struct nested', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructNested()

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructNestedFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 112)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 1267)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructNested()
  let reader = new prototest.StructNestedFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 112)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1, false)
  t.equal(struct2.f2, true)
  t.equal(struct2.f3, 0)
  t.equal(struct2.f4, 0xFF)
  t.equal(struct2.f5, '\0')
  t.equal(struct2.f6, '!')
  t.equal(struct2.f7, String.fromCharCode(0))
  t.equal(struct2.f8, String.fromCharCode(0x0444))
  t.equal(struct2.f9, 0)
  t.equal(struct2.f10, 127)
  t.equal(struct2.f11, 0)
  t.equal(struct2.f12, 0xFF)
  t.equal(struct2.f13, 0)
  t.equal(struct2.f14, 32767)
  t.equal(struct2.f15, 0)
  t.equal(struct2.f16, 0xFFFF)
  t.equal(struct2.f17, 0)
  t.equal(struct2.f18, 2147483647)
  t.equal(struct2.f19, 0)
  t.equal(struct2.f20, 0xFFFFFFFF)
  t.true(struct2.f21.eq(Int64.fromNumber(0)))
  t.true(struct2.f22.eq(Int64.fromNumber(9223372036854775807)))
  t.true(struct2.f23.eq(UInt64.fromNumber(0)))
  t.true(struct2.f24.eq(UInt64.fromNumber(0xFFFFFFFFFFFFFFFF)))
  t.equal(struct2.f25, 0.0)
  t.true(Math.abs(struct2.f26 - 123.456) < 0.0001)
  t.equal(struct2.f27, 0.0)
  t.true(Math.abs(struct2.f28 - -123.567e+123) < 1e+123)
  t.true(struct2.f29.eq(new Big('0')))
  t.true(struct2.f30.eq(new Big('123456.123456')))
  t.equal(struct2.f31, '')
  t.equal(struct2.f32, 'Initial string!')
  t.equal(struct2.f33.getTime(), new Date(Date.UTC(1970, 0, 1)).getTime())
  t.equal(struct2.f34.getTime(), new Date(Date.UTC(1970, 0, 1)).getTime())
  t.true(struct2.f35.getTime() > new Date(Date.UTC(2018, 1, 1)).getTime())
  t.true(struct2.f36.eq(new UUID()))
  t.false(struct2.f37.eq(new UUID()))
  t.true(struct2.f38.eq(new UUID('123e4567-e89b-12d3-a456-426655440000')))

  t.equal(struct2.f100, undefined)
  t.notEqual(struct2.f101, null)
  t.equal(struct2.f101, true)
  t.equal(struct2.f102, undefined)
  t.equal(struct2.f103, undefined)
  t.notEqual(struct2.f104, null)
  t.equal(struct2.f104, 0xFF)
  t.equal(struct2.f105, undefined)
  t.equal(struct2.f106, undefined)
  t.notEqual(struct2.f107, null)
  t.equal(struct2.f107, '!')
  t.equal(struct2.f108, undefined)
  t.equal(struct2.f109, undefined)
  t.notEqual(struct2.f110, null)
  t.equal(struct2.f110, String.fromCharCode(0x0444))
  t.equal(struct2.f111, undefined)
  t.equal(struct2.f112, undefined)
  t.notEqual(struct2.f113, null)
  t.equal(struct2.f113, 127)
  t.equal(struct2.f114, undefined)
  t.equal(struct2.f115, undefined)
  t.notEqual(struct2.f116, null)
  t.equal(struct2.f116, 0xFF)
  t.equal(struct2.f117, undefined)
  t.equal(struct2.f118, undefined)
  t.notEqual(struct2.f119, null)
  t.equal(struct2.f119, 32767)
  t.equal(struct2.f120, undefined)
  t.equal(struct2.f121, undefined)
  t.notEqual(struct2.f122, null)
  t.equal(struct2.f122, 0xFFFF)
  t.equal(struct2.f123, undefined)
  t.equal(struct2.f124, undefined)
  t.notEqual(struct2.f125, null)
  t.equal(struct2.f125, 2147483647)
  t.equal(struct2.f126, undefined)
  t.equal(struct2.f127, undefined)
  t.notEqual(struct2.f128, null)
  t.equal(struct2.f128, 0xFFFFFFFF)
  t.equal(struct2.f129, undefined)
  t.equal(struct2.f130, undefined)
  t.notEqual(struct2.f131, null)
  t.true(struct2.f131.eq(Int64.fromNumber(9223372036854775807)))
  t.equal(struct2.f132, undefined)
  t.equal(struct2.f133, undefined)
  t.notEqual(struct2.f134, null)
  t.true(struct2.f134.eq(UInt64.fromNumber(0xFFFFFFFFFFFFFFFF)))
  t.equal(struct2.f135, undefined)
  t.equal(struct2.f136, undefined)
  t.notEqual(struct2.f137, null)
  t.true(Math.abs(struct2.f137 - 123.456) < 0.0001)
  t.equal(struct2.f138, undefined)
  t.equal(struct2.f139, undefined)
  t.notEqual(struct2.f140, null)
  t.true(Math.abs(struct2.f140 - -123.567e+123) < 1e+123)
  t.equal(struct2.f141, undefined)
  t.equal(struct2.f142, undefined)
  t.notEqual(struct2.f143, null)
  t.true(struct2.f143.eq(new Big('123456.123456')))
  t.equal(struct2.f144, undefined)
  t.equal(struct2.f145, undefined)
  t.notEqual(struct2.f146, null)
  t.equal(struct2.f146, 'Initial string!')
  t.equal(struct2.f147, undefined)
  t.equal(struct2.f148, undefined)
  t.notEqual(struct2.f149, null)
  t.true(struct2.f149.getTime() > new Date(Date.UTC(2018, 1, 1)).getTime())
  t.equal(struct2.f150, undefined)
  t.equal(struct2.f151, undefined)
  t.notEqual(struct2.f152, null)
  t.true(struct2.f152.eq(new UUID('123e4567-e89b-12d3-a456-426655440000')))
  t.equal(struct2.f153, undefined)
  t.equal(struct2.f154, undefined)
  t.equal(struct2.f155, undefined)
  t.equal(struct2.f156, undefined)
  t.equal(struct2.f157, undefined)
  t.equal(struct2.f158, undefined)
  t.equal(struct2.f159, undefined)
  t.equal(struct2.f160, undefined)
  t.equal(struct2.f161, undefined)
  t.equal(struct2.f162, undefined)
  t.equal(struct2.f163, undefined)
  t.equal(struct2.f164, undefined)
  t.equal(struct2.f165, undefined)

  t.true(struct2.f1000.eq(prototest.EnumSimple.ENUM_VALUE_0))
  t.equal(struct2.f1001, undefined)
  t.true(struct2.f1002.eq(prototest.EnumTyped.ENUM_VALUE_2))
  t.equal(struct2.f1003, undefined)
  t.true(struct2.f1004.eq(prototest.FlagsSimple.FLAG_VALUE_0))
  t.equal(struct2.f1005, undefined)
  t.true(struct2.f1006.hasFlags(prototest.FlagsTyped.FLAG_VALUE_2 | prototest.FlagsTyped.FLAG_VALUE_4 | prototest.FlagsTyped.FLAG_VALUE_6))
  t.equal(struct2.f1007, undefined)
  t.equal(struct2.f1009, undefined)
  t.equal(struct2.f1011, undefined)

  t.equal(struct2.f1, struct1.f1)
  t.equal(struct2.f2, struct1.f2)
  t.equal(struct2.f3, struct1.f3)
  t.equal(struct2.f4, struct1.f4)
  t.equal(struct2.f5, struct1.f5)
  t.equal(struct2.f6, struct1.f6)
  t.equal(struct2.f7, struct1.f7)
  t.equal(struct2.f8, struct1.f8)
  t.equal(struct2.f9, struct1.f9)
  t.equal(struct2.f10, struct1.f10)
  t.equal(struct2.f11, struct1.f11)
  t.equal(struct2.f12, struct1.f12)
  t.equal(struct2.f13, struct1.f13)
  t.equal(struct2.f14, struct1.f14)
  t.equal(struct2.f15, struct1.f15)
  t.equal(struct2.f16, struct1.f16)
  t.equal(struct2.f17, struct1.f17)
  t.equal(struct2.f18, struct1.f18)
  t.equal(struct2.f19, struct1.f19)
  t.equal(struct2.f20, struct1.f20)
  t.true(struct2.f21.eq(struct1.f21))
  t.true(struct2.f22.eq(struct1.f22))
  t.true(struct2.f23.eq(struct1.f23))
  t.true(struct2.f24.eq(struct1.f24))
  t.equal(struct2.f25, struct1.f25)
  t.true(Math.abs(struct2.f26 - struct1.f26) < 0.0001)
  t.equal(struct2.f27, struct1.f27)
  t.true(Math.abs(struct2.f28 - struct1.f28) < 1e+123)
  t.true(struct2.f29.eq(struct1.f29))
  t.true(struct2.f29.eq(struct1.f29))
  t.equal(struct2.f31, struct1.f31)
  t.equal(struct2.f32, struct1.f32)
  t.equal(struct2.f33.getTime(), struct1.f33.getTime())
  t.equal(struct2.f34.getTime(), struct1.f34.getTime())
  t.equal(struct2.f35.getTime(), struct1.f35.getTime())
  t.true(struct2.f36.eq(struct1.f36))
  t.true(struct2.f37.eq(struct1.f37))
  t.true(struct2.f38.eq(struct1.f38))
  t.true(struct2.f39.eq(struct1.f39))
  t.true(struct2.f40.eq(struct1.f40))

  t.equal(struct2.f100, struct1.f100)
  t.equal(struct2.f101, struct1.f101)
  t.equal(struct2.f102, struct1.f102)
  t.equal(struct2.f103, struct1.f103)
  t.equal(struct2.f104, struct1.f104)
  t.equal(struct2.f105, struct1.f105)
  t.equal(struct2.f106, struct1.f106)
  t.equal(struct2.f107, struct1.f107)
  t.equal(struct2.f108, struct1.f108)
  t.equal(struct2.f109, struct1.f109)
  t.equal(struct2.f110, struct1.f110)
  t.equal(struct2.f111, struct1.f111)
  t.equal(struct2.f112, struct1.f112)
  t.equal(struct2.f113, struct1.f113)
  t.equal(struct2.f114, struct1.f114)
  t.equal(struct2.f115, struct1.f115)
  t.equal(struct2.f116, struct1.f116)
  t.equal(struct2.f117, struct1.f117)
  t.equal(struct2.f118, struct1.f118)
  t.equal(struct2.f119, struct1.f119)
  t.equal(struct2.f120, struct1.f120)
  t.equal(struct2.f121, struct1.f121)
  t.equal(struct2.f122, struct1.f122)
  t.equal(struct2.f123, struct1.f123)
  t.equal(struct2.f124, struct1.f124)
  t.equal(struct2.f125, struct1.f125)
  t.equal(struct2.f126, struct1.f126)
  t.equal(struct2.f127, struct1.f127)
  t.equal(struct2.f128, struct1.f128)
  t.equal(struct2.f129, struct1.f129)
  t.equal(struct2.f130, struct1.f130)
  t.true(struct2.f131.eq(struct1.f131))
  t.equal(struct2.f132, struct1.f132)
  t.equal(struct2.f133, struct1.f133)
  t.true(struct2.f134.eq(struct1.f134))
  t.equal(struct2.f135, struct1.f135)
  t.equal(struct2.f136, struct1.f136)
  t.true(Math.abs(struct2.f137 - struct1.f137) < 0.0001)
  t.equal(struct2.f138, struct1.f138)
  t.equal(struct2.f139, struct1.f139)
  t.true(Math.abs(struct2.f140 - struct1.f140) < 1e+123)
  t.equal(struct2.f141, struct1.f141)
  t.equal(struct2.f142, struct1.f142)
  t.true(struct2.f143.eq(struct1.f143))
  t.equal(struct2.f144, struct1.f144)
  t.equal(struct2.f145, struct1.f145)
  t.equal(struct2.f146, struct1.f146)
  t.equal(struct2.f147, struct1.f147)
  t.equal(struct2.f148, struct1.f148)
  t.equal(struct2.f149.getTime(), struct1.f149.getTime())
  t.equal(struct2.f150, struct1.f150)
  t.equal(struct2.f151, struct1.f151)
  t.true(struct2.f152.eq(struct1.f152))
  t.equal(struct2.f153, struct1.f153)
  t.equal(struct2.f154, struct1.f154)
  t.equal(struct2.f155, struct1.f155)
  t.equal(struct2.f156, struct1.f156)
  t.equal(struct2.f157, struct1.f157)

  t.true(struct2.f1000.eq(struct1.f1000))
  t.equal(struct2.f1001, struct1.f1001)
  t.true(struct2.f1002.eq(struct1.f1002))
  t.equal(struct2.f1003, struct1.f1003)
  t.true(struct2.f1004.eq(struct1.f1004))
  t.equal(struct2.f1005, struct1.f1005)
  t.true(struct2.f1006.eq(struct1.f1006))
  t.equal(struct2.f1007, struct1.f1007)
  t.end()
})

test('Serialization (Final): struct bytes', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructBytes()
  // noinspection JSUnresolvedFunction
  struct1.f1 = Uint8Array.from('ABC', x => x.charCodeAt(0))
  // noinspection JSUnresolvedFunction
  struct1.f2 = Uint8Array.from('test', x => x.charCodeAt(0))

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructBytesFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 120)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 25)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructBytes()
  let reader = new prototest.StructBytesFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 120)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1.length, 3)
  t.equal(struct2.f1[0], 'A'.charCodeAt(0))
  t.equal(struct2.f1[1], 'B'.charCodeAt(0))
  t.equal(struct2.f1[2], 'C'.charCodeAt(0))
  t.notEqual(struct2.f2, undefined)
  t.equal(struct2.f2.length, 4)
  t.equal(struct2.f2[0], 't'.charCodeAt(0))
  t.equal(struct2.f2[1], 'e'.charCodeAt(0))
  t.equal(struct2.f2[2], 's'.charCodeAt(0))
  t.equal(struct2.f2[3], 't'.charCodeAt(0))
  t.equal(struct2.f3, undefined)
  t.end()
})

test('Serialization (Final): struct array', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructArray()
  struct1.f1[0] = 48
  struct1.f1[1] = 65
  struct1.f2[0] = 97
  struct1.f2[1] = undefined
  struct1.f3[0] = Array.from('000', x => x.charCodeAt(0))
  struct1.f3[1] = Array.from('AAA', x => x.charCodeAt(0))
  struct1.f4[0] = Array.from('aaa', x => x.charCodeAt(0))
  struct1.f4[1] = undefined
  struct1.f5[0] = prototest.EnumSimple.ENUM_VALUE_1
  struct1.f5[1] = prototest.EnumSimple.ENUM_VALUE_2
  struct1.f6[0] = prototest.EnumSimple.ENUM_VALUE_1
  struct1.f6[1] = undefined
  struct1.f7[0] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2)
  struct1.f7[1] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3)
  struct1.f8[0] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2)
  struct1.f8[1] = undefined
  struct1.f9[0] = new prototest.StructSimple()
  struct1.f9[1] = new prototest.StructSimple()
  struct1.f10[0] = new prototest.StructSimple()
  struct1.f10[1] = undefined

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructArrayFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 125)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 954)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructArray()
  let reader = new prototest.StructArrayFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 125)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1.length, 2)
  t.equal(struct2.f1[0], 48)
  t.equal(struct2.f1[1], 65)
  t.equal(struct2.f2.length, 2)
  t.equal(struct2.f2[0], 97)
  t.equal(struct2.f2[1], undefined)
  t.equal(struct2.f3.length, 2)
  t.equal(struct2.f3[0].length, 3)
  t.equal(struct2.f3[0][0], 48)
  t.equal(struct2.f3[0][1], 48)
  t.equal(struct2.f3[0][2], 48)
  t.equal(struct2.f3[1].length, 3)
  t.equal(struct2.f3[1][0], 65)
  t.equal(struct2.f3[1][1], 65)
  t.equal(struct2.f3[1][2], 65)
  t.equal(struct2.f4.length, 2)
  t.notEqual(struct2.f4[0], undefined)
  t.equal(struct2.f4[0].length, 3)
  t.equal(struct2.f4[0][0], 97)
  t.equal(struct2.f4[0][1], 97)
  t.equal(struct2.f4[0][2], 97)
  t.equal(struct2.f4[1], undefined)
  t.equal(struct2.f5.length, 2)
  t.true(struct2.f5[0].eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.true(struct2.f5[1].eq(prototest.EnumSimple.ENUM_VALUE_2))
  t.equal(struct2.f6.length, 2)
  t.true(struct2.f6[0].eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.equal(struct2.f6[1], undefined)
  t.equal(struct2.f7.length, 2)
  t.true(struct2.f7[0].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.true(struct2.f7[1].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  t.equal(struct2.f8.length, 2)
  t.true(struct2.f8[0].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.equal(struct2.f8[1], undefined)
  t.equal(struct2.f9.length, 2)
  t.equal(struct2.f9[0].f2, true)
  t.equal(struct2.f9[0].f12, 0xFF)
  t.equal(struct2.f9[0].f32, 'Initial string!')
  t.equal(struct2.f9[1].f2, true)
  t.equal(struct2.f9[1].f12, 0xFF)
  t.equal(struct2.f9[1].f32, 'Initial string!')
  t.equal(struct2.f10.length, 2)
  t.notEqual(struct2.f10[0], undefined)
  t.equal(struct2.f10[0].f2, true)
  t.equal(struct2.f10[0].f12, 0xFF)
  t.equal(struct2.f10[0].f32, 'Initial string!')
  t.equal(struct2.f10[1], undefined)
  t.end()
})

test('Serialization (Final): struct vector', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructVector()
  struct1.f1[0] = 48
  struct1.f1[1] = 65
  struct1.f2[0] = 97
  struct1.f2[1] = undefined
  struct1.f3[0] = Array.from('000', x => x.charCodeAt(0))
  struct1.f3[1] = Array.from('AAA', x => x.charCodeAt(0))
  struct1.f4[0] = Array.from('aaa', x => x.charCodeAt(0))
  struct1.f4[1] = undefined
  struct1.f5[0] = prototest.EnumSimple.ENUM_VALUE_1
  struct1.f5[1] = prototest.EnumSimple.ENUM_VALUE_2
  struct1.f6[0] = prototest.EnumSimple.ENUM_VALUE_1
  struct1.f6[1] = undefined
  struct1.f7[0] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2)
  struct1.f7[1] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3)
  struct1.f8[0] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2)
  struct1.f8[1] = undefined
  struct1.f9[0] = new prototest.StructSimple()
  struct1.f9[1] = new prototest.StructSimple()
  struct1.f10[0] = new prototest.StructSimple()
  struct1.f10[1] = undefined

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructVectorFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 130)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 994)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructVector()
  let reader = new prototest.StructVectorFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 130)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1.length, 2)
  t.equal(struct2.f1[0], 48)
  t.equal(struct2.f1[1], 65)
  t.equal(struct2.f2.length, 2)
  t.equal(struct2.f2[0], 97)
  t.equal(struct2.f2[1], undefined)
  t.equal(struct2.f3.length, 2)
  t.equal(struct2.f3[0].length, 3)
  t.equal(struct2.f3[0][0], 48)
  t.equal(struct2.f3[0][1], 48)
  t.equal(struct2.f3[0][2], 48)
  t.equal(struct2.f3[1].length, 3)
  t.equal(struct2.f3[1][0], 65)
  t.equal(struct2.f3[1][1], 65)
  t.equal(struct2.f3[1][2], 65)
  t.equal(struct2.f4.length, 2)
  t.notEqual(struct2.f4[0], undefined)
  t.equal(struct2.f4[0].length, 3)
  t.equal(struct2.f4[0][0], 97)
  t.equal(struct2.f4[0][1], 97)
  t.equal(struct2.f4[0][2], 97)
  t.equal(struct2.f4[1], undefined)
  t.equal(struct2.f5.length, 2)
  t.true(struct2.f5[0].eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.true(struct2.f5[1].eq(prototest.EnumSimple.ENUM_VALUE_2))
  t.equal(struct2.f6.length, 2)
  t.true(struct2.f6[0].eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.equal(struct2.f6[1], undefined)
  t.equal(struct2.f7.length, 2)
  t.true(struct2.f7[0].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.true(struct2.f7[1].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  t.equal(struct2.f8.length, 2)
  t.true(struct2.f8[0].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.equal(struct2.f8[1], undefined)
  t.equal(struct2.f9.length, 2)
  t.equal(struct2.f9[0].f2, true)
  t.equal(struct2.f9[0].f12, 0xFF)
  t.equal(struct2.f9[0].f32, 'Initial string!')
  t.equal(struct2.f9[1].f2, true)
  t.equal(struct2.f9[1].f12, 0xFF)
  t.equal(struct2.f9[1].f32, 'Initial string!')
  t.equal(struct2.f10.length, 2)
  t.notEqual(struct2.f10[0], undefined)
  t.equal(struct2.f10[0].f2, true)
  t.equal(struct2.f10[0].f12, 0xFF)
  t.equal(struct2.f10[0].f32, 'Initial string!')
  t.equal(struct2.f10[1], undefined)
  t.end()
})

test('Serialization (Final): struct list', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructList()
  struct1.f1[0] = 48
  struct1.f1[1] = 65
  struct1.f2[0] = 97
  struct1.f2[1] = undefined
  struct1.f3[0] = Array.from('000', x => x.charCodeAt(0))
  struct1.f3[1] = Array.from('AAA', x => x.charCodeAt(0))
  struct1.f4[0] = Array.from('aaa', x => x.charCodeAt(0))
  struct1.f4[1] = undefined
  struct1.f5[0] = prototest.EnumSimple.ENUM_VALUE_1
  struct1.f5[1] = prototest.EnumSimple.ENUM_VALUE_2
  struct1.f6[0] = prototest.EnumSimple.ENUM_VALUE_1
  struct1.f6[1] = undefined
  struct1.f7[0] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2)
  struct1.f7[1] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3)
  struct1.f8[0] = prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2)
  struct1.f8[1] = undefined
  struct1.f9[0] = new prototest.StructSimple()
  struct1.f9[1] = new prototest.StructSimple()
  struct1.f10[0] = new prototest.StructSimple()
  struct1.f10[1] = undefined

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructListFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 131)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 994)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructList()
  let reader = new prototest.StructListFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 131)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1.length, 2)
  t.equal(struct2.f1[0], 48)
  t.equal(struct2.f1[1], 65)
  t.equal(struct2.f2.length, 2)
  t.equal(struct2.f2[0], 97)
  t.equal(struct2.f2[1], undefined)
  t.equal(struct2.f3.length, 2)
  t.equal(struct2.f3[0].length, 3)
  t.equal(struct2.f3[0][0], 48)
  t.equal(struct2.f3[0][1], 48)
  t.equal(struct2.f3[0][2], 48)
  t.equal(struct2.f3[1].length, 3)
  t.equal(struct2.f3[1][0], 65)
  t.equal(struct2.f3[1][1], 65)
  t.equal(struct2.f3[1][2], 65)
  t.equal(struct2.f4.length, 2)
  t.notEqual(struct2.f4[0], undefined)
  t.equal(struct2.f4[0].length, 3)
  t.equal(struct2.f4[0][0], 97)
  t.equal(struct2.f4[0][1], 97)
  t.equal(struct2.f4[0][2], 97)
  t.equal(struct2.f4[1], undefined)
  t.equal(struct2.f5.length, 2)
  t.true(struct2.f5[0].eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.true(struct2.f5[1].eq(prototest.EnumSimple.ENUM_VALUE_2))
  t.equal(struct2.f6.length, 2)
  t.true(struct2.f6[0].eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.equal(struct2.f6[1], undefined)
  t.equal(struct2.f7.length, 2)
  t.true(struct2.f7[0].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.true(struct2.f7[1].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  t.equal(struct2.f8.length, 2)
  t.true(struct2.f8[0].hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.equal(struct2.f8[1], undefined)
  t.equal(struct2.f9.length, 2)
  t.equal(struct2.f9[0].f2, true)
  t.equal(struct2.f9[0].f12, 0xFF)
  t.equal(struct2.f9[0].f32, 'Initial string!')
  t.equal(struct2.f9[1].f2, true)
  t.equal(struct2.f9[1].f12, 0xFF)
  t.equal(struct2.f9[1].f32, 'Initial string!')
  t.equal(struct2.f10.length, 2)
  t.notEqual(struct2.f10[0], undefined)
  t.equal(struct2.f10[0].f2, true)
  t.equal(struct2.f10[0].f12, 0xFF)
  t.equal(struct2.f10[0].f32, 'Initial string!')
  t.equal(struct2.f10[1], undefined)
  t.end()
})

test('Serialization (Final): struct set', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructSet()
  struct1.f1.add(48)
  struct1.f1.add(65)
  struct1.f1.add(97)
  struct1.f2.add(prototest.EnumSimple.ENUM_VALUE_1)
  struct1.f2.add(prototest.EnumSimple.ENUM_VALUE_2)
  struct1.f3.add(prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  struct1.f3.add(prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  let s1 = new prototest.StructSimple()
  s1.id = 48
  struct1.f4.add(s1)
  let s2 = new prototest.StructSimple()
  s2.id = 65
  struct1.f4.add(s2)

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructSetFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 132)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 635)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructSet()
  let reader = new prototest.StructSetFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 132)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  let found

  // Javascript sets are limited to check object key with custom key comparator!
  t.equal(struct2.f1.size, 3)
  t.true(struct2.f1.has(48))
  t.true(struct2.f1.has(65))
  t.true(struct2.f1.has(97))
  t.equal(struct2.f2.size, 2)
  found = false
  struct2.f2.forEach(value => { if (value.eq(prototest.EnumSimple.ENUM_VALUE_1)) found = true })
  t.true(found)
  found = false
  struct2.f2.forEach(value => { if (value.eq(prototest.EnumSimple.ENUM_VALUE_2)) found = true })
  t.true(found)
  t.equal(struct2.f3.size, 2)
  found = false
  struct2.f3.forEach(value => { if (value.eq(prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))) found = true })
  t.true(found)
  found = false
  struct2.f3.forEach(value => { if (value.eq(prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))) found = true })
  t.true(found)
  t.equal(struct2.f4.size, 2)
  found = false
  struct2.f4.forEach(value => { if (value.eq(s1)) found = true })
  t.true(found)
  found = false
  struct2.f4.forEach(value => { if (value.eq(s2)) found = true })
  t.true(found)
  t.end()
})

test('Serialization (Final): struct map', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructMap()
  struct1.f1.set(10, 48)
  struct1.f1.set(20, 65)
  struct1.f2.set(10, 97)
  struct1.f2.set(20, undefined)
  struct1.f3.set(10, Array.from('000', x => x.charCodeAt(0)))
  struct1.f3.set(20, Array.from('AAA', x => x.charCodeAt(0)))
  struct1.f4.set(10, Array.from('aaa', x => x.charCodeAt(0)))
  struct1.f4.set(20, undefined)
  struct1.f5.set(10, prototest.EnumSimple.ENUM_VALUE_1)
  struct1.f5.set(20, prototest.EnumSimple.ENUM_VALUE_2)
  struct1.f6.set(10, prototest.EnumSimple.ENUM_VALUE_1)
  struct1.f6.set(20, undefined)
  struct1.f7.set(10, prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  struct1.f7.set(20, prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  struct1.f8.set(10, prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  struct1.f8.set(20, undefined)
  let s1 = new prototest.StructSimple()
  s1.id = 48
  struct1.f9.set(10, s1)
  let s2 = new prototest.StructSimple()
  s2.id = 65
  struct1.f9.set(20, s2)
  struct1.f10.set(10, s1)
  struct1.f10.set(20, undefined)

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructMapFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 140)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 1074)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructMap()
  let reader = new prototest.StructMapFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 140)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1.size, 2)
  t.equal(struct2.f1.get(10), 48)
  t.equal(struct2.f1.get(20), 65)
  t.equal(struct2.f2.size, 2)
  t.equal(struct2.f2.get(10), 97)
  t.equal(struct2.f2.get(20), undefined)
  t.equal(struct2.f3.size, 2)
  t.equal(struct2.f3.get(10).length, 3)
  t.equal(struct2.f3.get(20).length, 3)
  t.equal(struct2.f4.size, 2)
  t.equal(struct2.f4.get(10).length, 3)
  t.equal(struct2.f4.get(20), undefined)
  t.equal(struct2.f5.size, 2)
  t.true(struct2.f5.get(10).eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.true(struct2.f5.get(20).eq(prototest.EnumSimple.ENUM_VALUE_2))
  t.equal(struct2.f6.size, 2)
  t.true(struct2.f6.get(10).eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.equal(struct2.f6.get(20), undefined)
  t.equal(struct2.f7.size, 2)
  t.true(struct2.f7.get(10).hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.true(struct2.f7.get(20).hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  t.equal(struct2.f8.size, 2)
  t.true(struct2.f8.get(10).hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.equal(struct2.f8.get(20), undefined)
  t.equal(struct2.f9.size, 2)
  t.equal(struct2.f9.get(10).id, 48)
  t.equal(struct2.f9.get(20).id, 65)
  t.equal(struct2.f10.size, 2)
  t.equal(struct2.f10.get(10).id, 48)
  t.equal(struct2.f10.get(20), undefined)
  t.end()
})

test('Serialization (Final): struct hash', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructHash()
  struct1.f1.set('10', 48)
  struct1.f1.set('20', 65)
  struct1.f2.set('10', 97)
  struct1.f2.set('20', undefined)
  struct1.f3.set('10', Array.from('000', x => x.charCodeAt(0)))
  struct1.f3.set('20', Array.from('AAA', x => x.charCodeAt(0)))
  struct1.f4.set('10', Array.from('aaa', x => x.charCodeAt(0)))
  struct1.f4.set('20', undefined)
  struct1.f5.set('10', prototest.EnumSimple.ENUM_VALUE_1)
  struct1.f5.set('20', prototest.EnumSimple.ENUM_VALUE_2)
  struct1.f6.set('10', prototest.EnumSimple.ENUM_VALUE_1)
  struct1.f6.set('20', undefined)
  struct1.f7.set('10', prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  struct1.f7.set('20', prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  struct1.f8.set('10', prototest.FlagsSimple.fromFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  struct1.f8.set('20', undefined)
  let s1 = new prototest.StructSimple()
  s1.id = 48
  struct1.f9.set('10', s1)
  let s2 = new prototest.StructSimple()
  s2.id = 65
  struct1.f9.set('20', s2)
  struct1.f10.set('10', s1)
  struct1.f10.set('20', undefined)

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructHashFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 141)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 1114)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructHash()
  let reader = new prototest.StructHashFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 141)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  t.equal(struct2.f1.size, 2)
  t.equal(struct2.f1.get('10'), 48)
  t.equal(struct2.f1.get('20'), 65)
  t.equal(struct2.f2.size, 2)
  t.equal(struct2.f2.get('10'), 97)
  t.equal(struct2.f2.get('20'), undefined)
  t.equal(struct2.f3.size, 2)
  t.equal(struct2.f3.get('10').length, 3)
  t.equal(struct2.f3.get('20').length, 3)
  t.equal(struct2.f4.size, 2)
  t.equal(struct2.f4.get('10').length, 3)
  t.equal(struct2.f4.get('20'), undefined)
  t.equal(struct2.f5.size, 2)
  t.true(struct2.f5.get('10').eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.true(struct2.f5.get('20').eq(prototest.EnumSimple.ENUM_VALUE_2))
  t.equal(struct2.f6.size, 2)
  t.true(struct2.f6.get('10').eq(prototest.EnumSimple.ENUM_VALUE_1))
  t.equal(struct2.f6.get('20'), undefined)
  t.equal(struct2.f7.size, 2)
  t.true(struct2.f7.get('10').hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.true(struct2.f7.get('20').hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2 | prototest.FlagsSimple.FLAG_VALUE_3))
  t.equal(struct2.f8.size, 2)
  t.true(struct2.f8.get('10').hasFlags(prototest.FlagsSimple.FLAG_VALUE_1 | prototest.FlagsSimple.FLAG_VALUE_2))
  t.equal(struct2.f8.get('20'), undefined)
  t.equal(struct2.f9.size, 2)
  t.equal(struct2.f9.get('10').id, 48)
  t.equal(struct2.f9.get('20').id, 65)
  t.equal(struct2.f10.size, 2)
  t.equal(struct2.f10.get('10').id, 48)
  t.equal(struct2.f10.get('20'), undefined)
  t.end()
})

test('Serialization (Final): struct hash extended', function (t) {
  // Create a new struct
  let struct1 = new prototest.StructHashEx()
  let s1 = new prototest.StructSimple()
  s1.id = 48
  struct1.f1.set(s1, new prototest.StructNested())
  let s2 = new prototest.StructSimple()
  s2.id = 65
  struct1.f1.set(s2, new prototest.StructNested())
  struct1.f2.set(s1, new prototest.StructNested())
  struct1.f2.set(s2, undefined)

  // Serialize the struct to the FBE stream
  let writer = new prototest.StructHashExFinalModel(new fbe.WriteBuffer())
  t.equal(writer.fbeType, 142)
  let serialized = writer.serialize(struct1)
  t.equal(serialized, writer.buffer.size)
  t.true(writer.verify())
  writer.next(serialized)

  // Check the serialized FBE size
  t.equal(writer.buffer.size, 4979)

  // Deserialize the struct from the FBE stream
  let struct2 = new prototest.StructHashEx()
  let reader = new prototest.StructHashExFinalModel(new fbe.ReadBuffer())
  t.equal(reader.fbeType, 142)
  reader.attachBuffer(writer.buffer)
  t.true(reader.verify())
  let deserialized = reader.deserialize(struct2)
  t.true(deserialized.size, reader.buffer.size)
  reader.next(deserialized.size)

  // Javascript maps are limited to get object key with custom key comparator!
  t.equal(struct2.f1.size, 2)
  struct2.f1.forEach((value, key) => { if (key.id === s1.id) t.true(value.f1002.eq(prototest.EnumTyped.ENUM_VALUE_2)) })
  struct2.f1.forEach((value, key) => { if (key.id === s2.id) t.true(value.f1002.eq(prototest.EnumTyped.ENUM_VALUE_2)) })
  t.equal(struct2.f2.size, 2)
  struct2.f2.forEach((value, key) => { if (key.id === s1.id) t.true(value.f1002.eq(prototest.EnumTyped.ENUM_VALUE_2)) })
  struct2.f2.forEach((value, key) => { if (key.id === s2.id) t.equal(value, undefined) })
  t.end()
})
